<?php
/**
 * Created by PhpStorm.
 * User: longli
 * VX: isa1589518286
 * Date: 2020/08/15
 * Time: 20:16
 * @link http://www.lmterp.cn
 */

namespace app\common\service\purchase;

use app\common\library\Tools;
use app\common\model\ChannelExpress;
use app\common\model\FinanceCash;
use app\common\model\FinancePayment;
use app\common\model\JobFlowModule;
use app\common\model\Producer;
use app\common\model\ProductPurchase;
use app\common\model\ProductStore;
use app\common\model\Purchase;
use app\common\model\SysAttachment;
use app\common\model\PurchaseException;
use app\common\model\PurchaseInfo;
use app\common\model\PurchaseReturn;
use app\common\model\PurchaseTrack;
use app\common\model\Warehouse;
use app\common\service\BaseService;
use app\common\service\finance\FinanceService;
use app\common\service\product\StockService;
use app\common\service\system\SystemService;
use app\common\status\BaseStatus;
use think\Db;
use think\exception\DbException;
use think\facade\Log;

class PurchaseService extends BaseService
{
    /**
     * 添加供应商
     * @param array $data 供应商数据
     * @return Producer|bool
     * @date 2020/11/26
     * @author longli
     */
    public function addProducer($data = [])
    {
        try
        {
            $pdata = Producer::getFilterField($data, '');
            if(empty($pdata)) return false;
            $pdata = Tools::trim($pdata);
            Db::startTrans();
            $producer = null;
            if(isset($pdata['producer_id'])) $producer = Producer::get($pdata['producer_id']);
            if(empty($producer) && isset($pdata['code'])) $producer = Producer::get(['code' => $pdata['code']]);
            if(!empty($producer))
            {
                $producer->save($pdata);
            }
            else
            {
                $producer = Producer::create($pdata)->refresh();
            }
            Db::commit();
            return $producer;
        }catch(DbException $exception)
        {
            Db::rollback();
            Log::info(sprintf("供应商录入失败，错误信息【%s】", $exception->getMessage()));
            return false;
        }
    }

    /**
     * 添加采购单
     * @param array $data 采购商品数据
     * @return Purchase|bool
     * @date 2020/11/03
     * @author longli
     */
    public function addPurchase($data = [])
    {
        try
        {
            $sdata = Purchase::getFilterField($data['purchase'], '');
            if(empty($sdata)) return false;
            $this->autoPurData($sdata);
            $sdata = Tools::trim($sdata);
            Db::startTrans();
            $purchase = null;
            if(isset($sdata['purchase_id'])) $purchase = Purchase::get($sdata['purchase_id']);
            if(isset($sdata['producer_id']) && ($producer = Producer::get($sdata['producer_id'])))
                $sdata['producer_name'] = $producer->name;
            if(!empty($purchase))
            {
                $purchase->save($sdata);
            }
            else
            {
                $sdata['purchase_sn'] = $this->generatePo();
                // $sdata['buyer_user_id'] = session('lmterp')->id;
                $purchase = Purchase::create($sdata)->refresh();
            }
            // 添加采购详情
            if(!empty($data['info'])) $this->addPurchaseInfo($purchase, $data['info']);
            // 添加附件信息
            if(!empty($data['attachment']))
                SystemService::getInstance()->addAttachments(Purchase::getTable(), $purchase->purchase_id, $data['attachment']);
            $this->computeTotalPrice($purchase);
            $purchase->save();
            Db::commit();
            return $purchase;
        }catch(DbException $exception)
        {
            Db::rollback();
            Log::info(sprintf("采购录入失败，错误信息【%s】", $exception->getMessage()));
            return false;
        }
    }

    /**
     * 自动填充采购信息
     * @param array $data 采购信息
     * @date 2020/11/04
     * @author longli
     */
    private function autoPurData(& $data = [])
    {
        if(!empty($data['warehouse_id']))
        {
            $auto = ['contacts', 'phone', 'address'];
            $warehouse = Warehouse::get($data['warehouse_id']);
            if(empty($warehouse)) return;
            foreach($auto as $k => $v)
            {
                if(is_numeric($k)) $k = $v;
                if(empty($data[$k]))
                {
                    $data[$k] = $warehouse->{$v};
                }
            }
        }
    }

    /**
     * 添加采购详情
     * @param Purchase $purchase 采购
     * @param array $info 采购详情
     * @date 2020/11/03
     * @author longli
     */
    public function addPurchaseInfo(Purchase $purchase, $info = [])
    {
        $ndids = [];
        foreach($info as $key => $item)
        {
            $data = PurchaseInfo::getFilterField($item, '');
            if(empty($data)) continue;
            $this->autoInfoData($purchase, $data);
            $data = Tools::trim($data);
            $infoObj = null;
            if(isset($data['info_id'])) $infoObj = PurchaseInfo::get($data['info_id']);
            $data['purchase_id'] = $purchase->purchase_id;
            if(empty($data['n_store_qty'])) $data['n_store_qty'] = $data['qty']; // 未入库数量
            if(!empty($infoObj))
            {
                $infoObj->save($data);
            }
            else
            {
                $infoObj = PurchaseInfo::create($data);
            }
            $ndids[] = $infoObj->info_id;
        }
        // 删除采购详情
        PurchaseInfo::destroy(function($query) use($purchase, $ndids)
        {
            $query->where('purchase_id', 'eq', $purchase->purchase_id);
            if(!empty($ndids)) $query->where('info_id', 'not in', $ndids);
        });
    }

    /**
     * 自动填充采购详情
     * @param Purchase $purchase 采购
     * @param array $data 采购详情
     * @date 2020/11/04
     * @author longli
     */
    private function autoInfoData(Purchase $purchase, & $data = [])
    {
        $store = null;
        if(!empty($data['sku']))
            $store = ProductStore::get(['sku' => $data['sku']]);
        else if(!empty($data['store_id']))
            $store = ProductStore::get($data['store_id']);
        if(!$store) return;
        $auto = ['store_id', 'sku', 'image_url'];
        foreach($auto as $k => $v)
        {
            if(is_numeric($k)) $k = $v;
            if(empty($data[$k]))
            {
                $data[$k] = $store->{$v};
            }
        }
        $data['unit'] = $store->product->unit->name_ch;
        $data['name_ch'] = $store->product->name_ch;
        // 如果未填链接链接则自动带入
        if(empty($data['url']))
        {
            $purl = ProductPurchase::get(['store_id' => $store->store_id, 'is_default' => ProductPurchase::IS_YES]);
            if(!empty($purl)) $data['url'] = $purl->url;
        }
        else if(!ProductPurchase::hasUrl($data['url']))
        {
            // 填采购链接判断是否重复，不重复则录入
            $producer = Producer::get($purchase->producer_id);
            $p = [
                'product_id' => $store->product->product_id,
                'store_id' => $store->store_id,
                'status' => ProductPurchase::IS_YES,
                'url' => $data['url'],
            ];
            if(!empty($producer))
            {
                $p += [
                    'producer_id' => $producer->producer_id,
                    'producer_name' => $producer->name,
                ];
            }
            ProductPurchase::create($p);
        }
    }

    /**
     * 添加采购追踪号
     * @param Purchase $purchase 采购单
     * @param string[] $data 跟踪信息
     * @param string[] $info 商品信息
     * @return PurchaseTrack|bool
     * @date 2020/12/18
     * @author longli
     */
    public function addTrack($purchase, $data = [], $info = [])
    {
        if(empty($purchase)) return false;
        $tData = PurchaseTrack::getFilterField($data, '');
        if(empty($tData)) return false;
        $tData = Tools::trim($tData);
        $tData['purchase_id'] = $purchase->purchase_id;
        $track = null;
        if(isset($tData['track_id'])) $track = PurchaseTrack::get($tData['track_id']);
        if(empty($track) && isset($tData['purchase_id']) && $tData['track_num'])
            $track = PurchaseTrack::get(['track_num' => $tData['track_num'], 'purchase_id' => $tData['purchase_id']]);
        if(isset($tData['express_id']) && empty($tData['logistics_name']) && ($express = ChannelExpress::get($tData['express_id'])))
            $tData['logistics_name'] = $express->logistics_name;
        try {
            Db::startTrans();
            $isUpdate = true;
            if(!empty($track))
            {
                $track->save($tData);
            }
            else
            {
                $track = PurchaseTrack::create($tData)->refresh();
                $isUpdate = false;
            }

            $idType = PurchaseTrack::getTable();
            if(empty($info)) $info = $purchase->info;
            foreach($info as $item)
            {
                $iData = [
                    'purchase_id' => $purchase->purchase_id,
                    'id_type' => $idType,
                    'ref_id' => $track->track_id,
                    'sku' => $item['sku'],
                    'qty' => $item['qty'],
                    'act_money' => '0',
                ];
                RExService::getInstance()->addInfo($iData);
            }
            // 更新采购单状态
            if($purchase->getData('order_status') < Purchase::ORDER_STATUS_SHIPPING)
            {
                $purchase->order_status = Purchase::ORDER_STATUS_SHIPPING;
                $purchase->save();
            }
            // 添加采购在途库存
            if(!$isUpdate) StockService::purchaseIngStock($track);
            // 提交事物
            Db::commit();
            return $track;
        }catch (DbException $exception)
        {
            Db::rollback();
            Log::info(sprintf("采购追踪号录入失败，错误信息【%s】", $exception->getMessage()));
            return false;
        }
    }

    /**
     * 删除采购单
     * @param int|int[] $ids 采购 id
     * @return bool
     * @date 2020/11/07
     * @author longli
     */
    public function deleteById($ids)
    {
        try
        {
            Db::startTrans();
            Purchase::destroy($ids);
            PurchaseInfo::destroy(function($query)use($ids){$query->whereIn("purchase_id", $ids);});
            PurchaseTrack::destroy(function($query)use($ids){$query->whereIn("purchase_id", $ids);});
            PurchaseReturn::destroy(function($query)use($ids){$query->whereIn("purchase_id", $ids);});
            SysAttachment::destroy(function($query)use($ids){$query->whereIn("ref_id", $ids)->where("id_type", Purchase::getTable());});
            PurchaseException::destroy(function($query)use($ids){$query->whereIn("purchase_id", $ids);});
            Db::commit();
            return true;
        }catch (DbException $exception)
        {
            Db::rollback();
            Log::info(sprintf("采购单删除失败，提示信息【%s】", $exception->getMessage()));
        }
        return false;
    }

    /**
     * 计算采购单总数（总金额，物流费用，商品总数...）
     * @param int|string|Purchase $purchase 采购id,采购单号,采购模型
     * @date 2020/11/06
     * @author longli
     */
    public function computeTotalPrice($purchase)
    {
        if(empty($purchase) || (!($purchase instanceof Purchase) && !($purchase = Purchase::getBySn($purchase)))) return;
        $qty = $total = 0;
        foreach($purchase->info as $info)
        {
            $total += $info->qty * $info->price;
            $qty += $info->qty;
        }
        foreach($purchase->payment as $payment)
        {
            if(in_array($payment->getData('pay_status'), [FinancePayment::PAY_STATUS_PART, FinancePayment::PAY_STATUS_ALL]))
                $purchase->pay_money += $payment->act_money;
        }
        // 开发票
        if($purchase->is_invoice == Purchase::IS_YES)
            $purchase->tax = $total * \think\facade\Config::get('param.purchase_tax', 0.17);
        $purchase->total_qty = $qty;
        $purchase->amo_money = $total;
        $purchase->total_money = $total + $purchase->tax + $purchase->logistics_price;
        $purchase->save();
    }

    /**
     * 判决是否为当前登录用户的采购单
     * @return bool
     * @date 2020/12/03
     * @author longli
     */
    public function isMyPurchase($ids)
    {
        $user = session("lmterp");
        foreach(Purchase::where("purchase_id", "in", $ids)->whereOr("purchase_sn", "in", $ids)->select() as $purchase)
        {
            if($purchase->create_by != $user->id) return false;
        }
        return true;
    }

    /**
     * 采购下单
     * @param array|string $purIds 采购id
     * @return array
     * @date 2020/12/20
     * @author longli
     */
    public function business($purIds = [])
    {
        $user = session("lmterp");
        try
        {
            $isAuto = \think\facade\Config::get('param.purchase_auto_payment', 0);
            $inId = [];
            Db::startTrans();
            foreach(Purchase::whereIn("purchase_id", $purIds)->with(['info'])->select() as $purchase)
            {
                if(!JobFlowModule::isCheckFinish($purchase)) continue;
                $inId[] = $purchase->purchase_id;
                $purchase->buyer_user_id = $user->id;
                $purchase->business_date = Tools::now();
                $purchase->order_status = Purchase::ORDER_STATUS_GENERATE;
                $purchase->save();
                // 生成付款单
                if($isAuto) $this->paymentDate($purchase);
            }
            Db::commit();
            return $inId;
        }catch(DbException $exception)
        {

            Log::info(sprintf("采购下单【%s】异常，异常信息【%s】", (is_array($purIds) ? join(', ', $purIds) : $purIds), $exception->getMessage()));
            Db::rollback();
            return [];
        }
    }

    /**
     * 生成采购付款单
     * @param Purchase $purchase
     * @return bool|string
     * @date 2020/12/20
     * @author longli
     */
    public function paymentDate($purchase)
    {
        $purchase = Purchase::getObj($purchase);
        if(($msg = $this->checkIsPayment($purchase)) !== true) return $msg;
        $payType = $purchase->getData('pay_type');
        $idType = Purchase::getTable();
        // 付款单是否存在
        if($purchase->getData("pay_status") == FinancePayment::PAY_STATUS_APPLY || FinancePayment::hasOrder($purchase->purchase_sn, $idType))
            return "【{$purchase->purchase_sn}】已生成过付款单";
        $totalMoney = $purchase->total_money; // 应该付总额
        // 需要开发票，默认为 17% 的税率
        if($purchase->is_invoice == Purchase::IS_YES
            && $purchase->producer->is_free_tax == Producer::IS_NO) $totalMoney += $purchase->tax;

        // 获取账期时间
        $creditDay = Tools::addDate($purchase->credit_day);

        $finance = FinanceService::getInstance();
        $data = [
            'biz_date' => $creditDay, // 应付款日期
            'bank'  => $purchase->producer->bank, // 银行
            'bank_address'  => $purchase->producer->bank_address, // 银行地址
            'bank_user'  => $purchase->producer->bank_user, // 户名
            'account'  => $purchase->producer->account, // 收款账号
            'pay_type'  => $payType, // 支付方式
            'act_money'  => $totalMoney - $purchase->pro_money, // 应付金额
            'ref_type'  => BaseStatus::REF_TYPE_PURCHASE, // 业务类型
            'ref_id_type'  => $idType, // 业务主表
            'ref_sn'  => $purchase->purchase_sn, // 业务单号
            'tax'  => $purchase->tax, // 税
            'is_invoice'  => $purchase->is_invoice, // 是否开发票
            'cost_desc'  => '采购费用' . ($purchase->tax > 0 ? ' + 税费' : ''), // 费用说明
        ];
        if(in_array($payType, [FinancePayment::PAY_TYPE_BEFORE, FinancePayment::PAY_TYPE_CREDIT]))
        {
            // 预付款
            $beforePay = $purchase->producer->before_pay / 100 * $purchase->amo_money; // 获取预付款百分比
            // 预付金额
            if($beforePay > 0)
            {
                $data['pay_type'] = FinancePayment::PAY_TYPE_BEFORE;
                $data['biz_date'] = date('Y-m-d');
                $data['act_money'] = $beforePay;
                $data['tax'] = 0;
                $data['cost_desc'] = '采购预付款';
                $finance->addPayment($data);
            }
            // 后付金额
            $data['biz_date'] = $creditDay;
            $data['act_money'] = $totalMoney - $beforePay - $purchase->pro_money;
            $data['tax'] = $purchase->tax;
            $data['pay_type'] = FinancePayment::PAY_TYPE_CREDIT;
            $data['cost_desc'] = '采购款账期';
            $finance->addPayment($data);
        }
        elseif($payType == FinancePayment::PAY_TYPE_AFTER_PAYMENT)
        {
            // 货到付款
            $data['biz_date'] = Tools::parseTime($purchase->recv_date);
            $finance->addPayment($data);
        }
        else
        {
            // 其它情况
            $finance->addPayment($data);
        }
        $purchase->pay_status = FinancePayment::PAY_STATUS_APPLY;
        $purchase->save();
        return true;
    }

    /**
     * 检查采购单是否可以生成付款单
     * @param Purchase $purchase 采购单
     * @return bool|string
     * @date 2020/12/25
     * @author longli
     */
    public function checkIsPayment(Purchase $purchase)
    {
        if(empty($purchase)) return "采购单不存在";
        if(!in_array($purchase->getData('order_status'), [
            Purchase::ORDER_STATUS_GENERATE,
            Purchase::ORDER_STATUS_EX,
            Purchase::ORDER_STATUS_RET,
        ])) return "采购单【{$purchase->purchase_sn}】还未下单，不能生成付款单";
        if($purchase->getData('pay_type') == FinancePayment::PAY_TYPE_AFTER_PAYMENT
            && empty($purchase->recv_date)) return "采购单【{$purchase->purchase_sn}】未收到货，不能生成付款单";
        return true;
    }

    /**
     * 根据追踪号/采购单号 获取获取采购单
     * @param string $po 采购单号、追踪号
     * @return Purchase|PurchaseTrack|null
     * @date 2020/12/25
     * @author longli
     */
    public function getByPoTrack($po)
    {
        // 采购单存在
        $po = trim($po);
        if($pur = Purchase::with(['info'])->where("purchase_sn", trim($po))->find()) return $pur;
        // 追踪号存在
        if($track = PurchaseTrack::with(['purchase', 'info'])->where("track_num", $po)->order("is_recv")->find()) return $track;
        return null;
    }

    /**
     * 采购单收货质检
     * @param int|Purchase $purchase 采购单，或者采购id
     * @param array $infoData 收货详情
     * @return bool|string
     * @date 2020/12/27
     * @author longli
     * @example
     * [
     *     "track_num" => "123456",
     *     "success" => [
     *           [
     *              "sku" => "A001",
     *              "qty" => 1,
     *              "remark" => "test",
     *          ],
     *     ],
     *     "exception" => [
     *          [
     *              "sku" => "A001",
     *              "qty" => 1,
     *              "remark" => "error",
     *              "exe_type" => 5,
     *          ],
     *     ],
     * ]
     */
    public function recvByPurId($purchase, $infoData = [])
    {
        $purchase = Purchase::getObj($purchase);
        if(empty($purchase)) return "采购单不存在";
        if($purchase->getData('order_status') < Purchase::ORDER_STATUS_OUT)
            return "采购单【{$purchase->purchase_sn}】状态为【{$purchase->order_status}】不能收货";
        if($purchase->isInStoreAll()) return "已全部入库";
        if(!empty($infoData['track_num']) && PurchaseTrack::isRecv($infoData['track_num'], $purchase->purchase_id))
            return "追踪号【{$infoData['track_num']}】已收过货";
        try
        {
            Db::startTrans();
            // 采购到货
            $purchase->recvPur();
            // 更新追踪号状态
            if(!empty($infoData['track_num']))
            {
                $tInfo = !empty($infoData['success']) ? $infoData['success'] : [];
                $this->received($purchase, $infoData['track_num'], $tInfo);
            }
            $infoData = Tools::trim($infoData);
            // 收货成功
            if(!empty($infoData['success']))
            {
                foreach($infoData['success'] as $succ)
                {
                    foreach($purchase->info as $info)
                    {
                        if($info->sku == $succ['sku'])
                        {
                            $qty = intval($succ['qty']);
                            if($qty < 1) continue;
                            $info->store_qty += $qty;
                            $info->n_store_qty = $info->getNotStoreQty();
                            $info->remark = !empty($succ['remark']) ? $succ['remark'] : '';
                            if($info->getData('store_status') < PurchaseInfo::STORE_IN_ING)
                                $info->store_status = PurchaseInfo::STORE_IN_ING;
                            $info->save();
                            break;
                        }
                    }
                }
                if($purchase->getData('order_status') < Purchase::ORDER_STATUS_IN)
                {
                    $purchase->order_status = Purchase::ORDER_STATUS_IN;
                    $purchase->save();
                }
            }
            // 收货异常
            if(!empty($infoData['exception']))
            {
                foreach($infoData['exception'] as $exce)
                {
                    $qty = intval($exce['qty']);
                    if($qty < 1) continue;
                    $eData = [
                        'purchase_id' => $purchase->purchase_id,
                        'sku' => $exce['sku'],
                        'exception_type' => $exce['exe_type'],
                        'remark' => $exce['remark'],
                    ];
                    $eInfo = [
                        'sku' => $exce['sku'],
                        'qty' => $qty
                    ];
                    RExService::getInstance()->addException($eData, $eInfo);
                }
            }
            Db::commit();
        }catch (DbException $exception)
        {
            Log::info(sprintf("采购单【%s】收货异常，异常信息【%s】", $purchase->purchase_sn, $exception->getMessage()));
            Db::rollback();
            return "收货失败，请稍后再试...";
        }
        return true;
    }

    /**
     * 采购追踪号到货
     * @param int|Purchase $purchase 采购ID, 或者采购单
     * @param string $trackNum 追踪号
     * @param array $tInfo 追踪号商品详情
     * @return bool|string
     * @date 2020/12/28
     * @author longli
     */
    public function received($purchase, $trackNum, $tInfo = [])
    {
        $purchase = Purchase::getObj($purchase);
        if(empty($purchase)) return "采购单不存在";
        if(PurchaseTrack::isRecv($trackNum)) return true;
        try
        {
            Db::startTrans();
            $purchase->recvPur();
            // 追踪号未录入则自动添加追踪号
            if(!PurchaseTrack::recv($trackNum, $purchase->purchase_id))
            {
                $tData = [
                    'track_num' => $trackNum,
                    'pay_type' => PurchaseTrack::PAY_TYPE_T,
                ];
                $this->addTrack($purchase, $tData, $tInfo);
                PurchaseTrack::recv($trackNum, $purchase->purchase_id);
            }
            // 采购到货
            $this->recvByPurId($purchase, ['track_num' => $trackNum, 'success' => $tInfo]);
            Db::commit();
        }catch (DbException $exception)
        {
            Log::info(sprintf("采购单号【%s】到货更新状态失败，错误信息【%s】", $purchase->purchase_sn, $exception->getMessage()));
            Db::rollback();
            return false;
        }
        return true;
    }

    /**
     * 核销采购单
     * @param int|Purchase $purchase 采购id, 采购单
     * @return bool|string
     * @date 2021/04/08
     * @author longli
     */
    public function verification($purchase)
    {
        $purchase = Purchase::getObj($purchase);
        if(empty($purchase)) return "采购单不存在";
        if($purchase->isInStoreAll())
        {
            $purchase->order_status = Purchase::ORDER_STATUS_IN_SUCC;
            $purchase->save();
        }
        if(!in_array($purchase->getData('order_status'), [Purchase::ORDER_STATUS_FCHE_ING, Purchase::ORDER_STATUS_IN_SUCC]))
            return "采购单【{$purchase->purchase_sn}】状态为【{$purchase->order_status}】不能核销";
        if(!in_array($purchase->getData('pay_status'), [FinancePayment::PAY_STATUS_ALL, FinancePayment::PAY_STATUS_RET_ALL, FinancePayment::PAY_STATUS_RET_PART]))
            return "采购单【{$purchase->purchase_sn}】支付状态为【{$purchase->pay_status}】不能核销";

        $payMoney = FinancePayment::getPaidMoney($purchase->purchase_sn, $purchase->getTable()); // 已支付总金额
        $renMoney = $exceMoney = 0; // 退款/异常金额
        $stMoney = $purchase->logistics_price; // 已入库商品金额
        foreach($purchase->pren as $ren)
        {
            $renMoney += FinanceCash::getTotalMoneyBySn($ren->return_sn, PurchaseReturn::getTable());
        }
        foreach($purchase->info as $info)
        {
            // 单价 * 已入库数量
            $stMoney += $info->price * ($info->stock_qty > $info->qty ? $info->qty : $info->stock_qty);
            // 单价 * 确认异常数量
            $exceMoney += $info->price * $info->exce_qty;
        }
        // 如果退货金额和异常金额不相等，把异常数量的金额加上已入库金额
        if($renMoney != $exceMoney) $stMoney += $exceMoney;
        $payMoney += $purchase->pro_money - $purchase->tax - $renMoney;
        if(($diff = bcsub($payMoney, $stMoney, 4)) != 0)
        {
            $diff = abs($diff);
            return "采购单【{$purchase->purchase_sn}】已入库和已支付金额相差【{$diff}】元不能核销";
        }
        // 更新采购单状态
        $purchase->order_status = Purchase::ORDER_STATUS_CHE_OK;
        $purchase->finish_date = Tools::now();
        $purchase->save();
        // 手动审核
        if(!Tools::isCli() && ($user = session('lmterp'))) Log::info("【{$user->nickname}】手动核销采购单【{$purchase->purchase_sn}】");
        return true;
    }

    /**
     * 生成采购PO号
     * @return string
     * @date 2020/11/04
     * @author longli
     */
    public function generatePo()
    {
        return self::generateSn('PO');
    }
}